/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		overheap.cpp
 * PURPOSE:		an optional debug heap to be seperately compiled and linked,
 *				records all allocations and uses page protection to expose overflows
 *				not for use in release
 */

#include <windows.h>

static const SIZE_T PAGE_SIZE = 0x1000;

static const ULONG AllocStorageCt = 0x100000;

PWCHAR Allocs[AllocStorageCt];
volatile LONG AllocNum = 0;

volatile LONG AllocCt = 0;

void Break(){}

void *__cdecl operator new(size_t sz)
{
	if(sz > PAGE_SIZE)
		Break();

	InterlockedIncrement(&AllocCt);

	SIZE_T ResSize = ((sz - 1) / PAGE_SIZE + 2) * PAGE_SIZE;

	PVOID ResFull = VirtualAlloc(0, ResSize, MEM_RESERVE, PAGE_NOACCESS);

	PVOID Committed = VirtualAlloc(ResFull, ResSize - PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);

	PVOID Ret = (PVOID)(((ULONG_PTR)Committed + ResSize - PAGE_SIZE) - sz);

	Allocs[InterlockedIncrement(&AllocNum)] = (PWCHAR)Ret;

	//*(PULONG)((ULONG_PTR)Ret - 4) = AllocNum;

	return Ret;
}

void *__cdecl operator new[](size_t sz)
{
	return operator new(sz);
}

void __cdecl operator delete(void *p)
{
	*((char *)p) = 0;

	InterlockedDecrement(&AllocCt);

	ULONG OrigAllocNum = 0;//= *(PULONG)((ULONG_PTR)p - 4);
	for(ULONG i = 0; i < AllocStorageCt; i++)
		if(Allocs[i] == p)
		{
			OrigAllocNum = i;
			break;
		}

	Allocs[OrigAllocNum] = 0;

	BOOL r = VirtualFree((PVOID)((ULONG_PTR)p & ~0xFFF), 0, MEM_RELEASE); //leaky
	if(!r)
	{
		ULONG Error = GetLastError();
		Break();
	}
}

void __cdecl operator delete[](void *p)
{
	operator delete(p);
}

void __stdcall DBG_CheckAllocs()
{
	for(ULONG i = 0; i < AllocStorageCt; i++)
		if(Allocs[i])
			Break();
}